﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Diagnostics;

namespace DVK.SP2007
{
    /// <summary>
    /// Main logger class, that works with the existing System.Diagnostics tracing api.
    /// </summary>
    public class Logger : TraceSource
    {
        /// <summary>
        /// This is used for general application logging.
        /// </summary>
        public const string ApplicationLoggingSource = "DVK.SP2007";

        /// <summary>
        /// Singleton of Logger for application wide logging
        /// </summary>
        private static Logger _logger;

        /// <summary>
        /// Gets the singleton instance of Logger.
        /// This uses the source of <paramref name="ApplicationLoggingSource"/>.
        /// The default logging level is Error.
        /// </summary>
        /// <value>The instance.</value>
        public static Logger Instance
        {
            get
            {
                if (_logger == null)
                {
                    _logger = new Logger(ApplicationLoggingSource);
                }
                return _logger;
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Logger"/> class.
        /// 
        /// <remarks>
        /// Default SourceLevel for logging is Error. This means, only error messages are logged.
        /// You can change the logging level for sources using the configuration (see example below).
        /// </remarks>
        /// <code>
        /// &lt;system.diagnostics&gt;
        ///     &lt;sources&gt;
        ///         &lt;source name="DVK.SP2007" switchName="sharedSwitch"&gt;
        ///             &lt;!-- You can add additional listeners here or use shared listeners --&gt;
        ///         &lt;/source&gt; 
        ///     &lt;/sources&gt;
        ///     &lt;switches&gt; 
        ///         &lt;!-- Logging from Information level. --&gt;
        ///         &lt;add name="sharedSwitch" value="Information"/&gt; 
        ///     &lt;/switches&gt;
        /// &lt;/system.diagnostics&gt;
        /// </code>
        /// </summary>
        /// <param name="name">The name.</param>
        public Logger(string name) : this(name, SourceLevels.Error) {}

        /// <summary>
        /// Initializes a new instance of the <see cref="Logger"/> class.
        /// 
        /// It also adds the default tracelisteners (EventLogTraceListener).
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="loggingLevel">The logging level.</param>
        public Logger(string name, SourceLevels loggingLevel)
            : base(name, loggingLevel)
        {
            bool hasEventLogTraceListener = false;
            TraceListener tempDefaultListener = null;
            foreach (TraceListener listener in Listeners)
            {
                if (listener is DefaultTraceListener)
                {
                    tempDefaultListener = listener;
                }
                if (listener is EventLogTraceListener)
                {
                    hasEventLogTraceListener = true;
                }
            }
            //default tracelistener is not required
            if (tempDefaultListener != null)
            {
                this.Listeners.Remove(tempDefaultListener);
            }
            //Add eventlog tracelistener, if it missing
            if (!hasEventLogTraceListener)
            {
                this.Listeners.Add(new EventLogTraceListener(this.Name));
            }
        }

        /// <summary>
        /// Logs informative messages to the trace listeners.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="messageParamters">The message paramters.</param>
        public void LogInformative(string message, params object[] messageParamters)
        {
            TraceData(
                TraceEventType.Information,
                1, /*Static event id for informative messages */
                string.Format(message, messageParamters)
                );
        }

        /// <summary>
        /// Logs error messages to the trace listeners.
        /// </summary>
        /// <param name="eventId">The event id.</param>
        /// <param name="message">The message.</param>
        /// <param name="messageParamters">The message paramters.</param>
        public void LogError(LoggerEvents eventId, string message, params object[] messageParamters)
        {
            LogError(eventId, null, message, messageParamters);
        }

        /// <summary>
        /// Logs error messages to the trace listeners.
        /// </summary>
        /// <param name="eventId">The event id.</param>
        /// <param name="exc">The exc.</param>
        /// <param name="message">The message.</param>
        /// <param name="messageParamters">The message paramters.</param>
        public void LogError(LoggerEvents eventId, Exception exc, string message, params object[] messageParamters)
        {
            string data = string.Format(message, messageParamters);
            data = eventId.ToString() + " : " + data;
            if (exc != null)
            {
                data = data + "\n\n Exception details: \n" + exc.ToString();
            }
            TraceData(
                TraceEventType.Error,
                GetAsInt<LoggerEvents>(eventId),
                data
                );
        }
        /// <summary>
        /// Gets enum value as int. This requires the enum values to be of type int.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eventId">The event id.</param>
        /// <returns>int value of enum</returns>
        private static int GetAsInt<T>(T eventId)
        {
            return (int)Enum.Parse(typeof(T), eventId.ToString());
        }
    }

}
